/*
*********************************************************************************************************
*                                               OS_CPU_C.C
*
*   Copyright 2003, Validated Software Corporation, Lafayette, CO
*   All Rights Reserved
*
*   Author:     Scott N.
*   Date:       03-Sep-03
*
*   References:
*   $Workfile: OS_CPU_C.C $
*
*   Description:    These are the C level OS support routines
*                   for the TMS320C6414 port on Code Composer Studio
*
*   Contents:
*              void setTickISR (int setting);  CONTROL CALL TO OSTimeTick (UCIT-SysTimer only).
*              void interrupt TimerOneTick(void)   SYSTEM TIMER INTERRUPT VECTOR
*              BOOLEAN areInterruptsEnabled (void) RETURN TRUE IF INTERRUPTS ENABLED
*              BOOLEAN enableInterrupts (void)  ENABLE INTERRUPTS
*              void  OS_CPU_Init (void) CPU INITIALIZATION
*              void  OS_CPU_InitTick (void) TICKER INITIALIZATION
*              OS_STK *OSTaskStkInit (void (*task)(void *pd), void *p_arg, OS_STK *ptos, INT16U opt)
*                                        INITIALIZE A TASK'S STACK
*    interrupt void InterruptNotEnabled(void)  CATCH-ALL INTERRUPT VECTOR
*
*   Revision History - latest change on top
*
*   $Log:  $
*
*********************************************************************************************************
*/

/*#define     OS_CPU_GLOBALS*/
#include "..\INCLUDES.H"

/*
*********************************************************************************************************
*                                        System Timer ISR (Timer 1)
*
* Description: This is the system timer ISR
*
* Note(s):
*			This implementation of UCOS-II requires that the IRP and CSR registers be saved
*			upon entry into any interrupt and restored upon exit.  Need to save the registers as locals
*	 		so each context has its own copy.
*
*********************************************************************************************************
*/

void interrupt TimerOneTick(void)
{
    const unsigned int iirp = IRP;  /* LOCAL copy of IRP and CSR to be restored upon */
    const unsigned int icsr = CSR;  /* return from this ISR.                         */

    OSIntEnter();                   /* tell the OS that we're in an interrupt        */
    OSTimeTick();           /* Call OS timer tick                                    */
    OSIntExit();            /* Task switch if we can                                 */

	IRP = iirp;
	CSR = icsr;
	return;
}

/*
*********************************************************************************************************
*                                        Return the state of global interrupts.
*
* Description: This function returns 1 if interrupts are enabled, otherwise 0.
*
* Note(s):   Only the global interrupt enable bit is examined.  Specific device interrupts may
*            or may not be enabled as controlled by the IER and device initialization.
*
*********************************************************************************************************
*/
BOOLEAN areInterruptsEnabled (void)
{
    /* The global interrupt enable bit is the lowest order bit of the CSR. */
    return (CSR & 0x1);
}


/*
*********************************************************************************************************
*                                       Enable interrupts
*
* Description: This function enables interrupts.
*
* Returns:   This function returns 1 if the processor's global interrupt enable bit was already
*            set when this function was called, else 0.
*
*
* Note(s):   MicroCOS uses OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL() to protect critical
*            regions.  Their implementation disables interrupts during the critical region,
*            then sets interrupts back to what they were.  They are to be used in pairs.
*            Calling OS_EXIT_CRITICAL() alone when interrupts are already off will not turn
*            them on.
*
*            This function only sets the processor's GLOBAL interrupt bit.  The OSTaskStkInit
*            function turns on interrupts for the timer (level 15) and maskable interrupts
*            generally (2nd lowest order bit of IER).
*
*
*********************************************************************************************************
*/
BOOLEAN enableInterrupts (void)
{
    BOOLEAN previousState = areInterruptsEnabled();

    /* The global interrupt enable bit is the lowest order bit of the CSR. */
    CSR |= 0x1;

    return previousState;
}

/*
*********************************************************************************************************
*                                        INITIALIZE A TASK'S STACK
*
* Description: This function is called by either OSTaskCreate() or OSTaskCreateExt() to initialize the
*              stack frame of the task being created.  This function is highly processor specific.
*
* Arguments  : task          is a pointer to the task code
*
*              p_arg         is a pointer to a user supplied data area that will be passed to the task
*                            when the task first executes.
*
*              ptos          is a pointer to the top of stack.  It is assumed that 'ptos' points to
*                            a 'free' entry on the task stack.  If OS_STK_GROWTH is set to 1 then
*                            'ptos' will contain the HIGHEST valid address of the stack.  Similarly, if
*                            OS_STK_GROWTH is set to 0, the 'ptos' will contains the LOWEST valid address
*                            of the stack.
*
*              opt           specifies options that can be used to alter the behavior of OSTaskStkInit().
*                            (see uCOS_II.H for OS_TASK_OPT_???).
*
* Returns    : Always returns the location of the new top-of-stack' once the processor registers have
*              been placed on the stack in the proper order.
*
* Note(s)    : Interrupts are enabled when your task starts executing. You can change this by setting the
*              PSW to 0x0002 instead.  In this case, interrupts would be disabled upon task startup.  The
*              application code would be responsible for enabling interrupts at the beginning of the task
*              code.  You will need to modify OSTaskIdle() and OSTaskStat() so that they enable
*              interrupts.  Failure to do this will make your system crash!
*********************************************************************************************************
*/
OS_STK *OSTaskStkInit(void (*task)(void *pd), void *p_arg, OS_STK *ptos, INT16U opt)
{
    REGISTER_FRAME  *Frame, *StackBottom;
    unsigned int    *FirstFreeCellInStack ;
    unsigned int    Temp, Temp1;

   /*------------------------------------------------------------------------
      THE SP MUST BE ALIGNED ON AN 8-BYTE BOUNDARY.
      The FRAME must be an alignment of that also
    ------------------------------------------------------------------------*/

    opt         =   opt;      // prevent compiler warning

    Frame       =   (REGISTER_FRAME *)((int)ptos &~7 );
    StackBottom =   Frame ;
    Temp1       =   (unsigned int)Frame;
    Temp        =   (sizeof(REGISTER_FRAME) - sizeof(unsigned int)) ;        // Decrement pointer to simulate pushing a frame
    Frame       =   (REGISTER_FRAME *)(Temp1 - Temp);


    Frame->A0   =   0x0A0;
    Frame->A1   =   0x0A1;
    Frame->A2   =   0x0A2;
    Frame->A3   =   0x0A3;
    Frame->A4   =   (unsigned int)p_arg; /* data pointer first argument */
    Frame->A5   =   0x0A5;
    Frame->A6   =   0x0A6;
    Frame->A7   =   0x0A7;
    Frame->A8   =   0x0A8;
    Frame->A9   =   0x0A9;
    Frame->A10  =   0x0A10;
    Frame->A11  =   0x0A11;
    Frame->A12  =   0x0A12;
    Frame->A13  =   0x0A13;
    Frame->A14  =   0x0A14;
    Frame->A15  =   0x0A15;
    Frame->A16  =   0x0A16;
    Frame->A17  =   0x0A17;
    Frame->A18  =   0x0A18;
    Frame->A19  =   0x0A19;
    Frame->A20  =   0x0A20;
    Frame->A21  =   0x0A21;
    Frame->A22  =   0x0A22;
    Frame->A23  =   0x0A23;
    Frame->A24  =   0x0A24;
    Frame->A25  =   0x0A25;
    Frame->A26  =   0x0A26;
    Frame->A27  =   0x0A27;
    Frame->A28  =   0x0A28;
    Frame->A29  =   0x0A29;
    Frame->A30  =   0x0A30;
    Frame->A31  =   0x0A31;


    Frame->B0   =   0x0B0;
    Frame->B1   =   0x0B1;
    Frame->B2   =   0x0B2;
    Frame->B3   =   0x0B3;
    Frame->B4   =   0x0B4;
    Frame->B5   =   0x0B5;
    Frame->B6   =   0x0B6;
    Frame->B7   =   0x0B7;
    Frame->B8   =   0x0B8;
    Frame->B9   =   0x0B9;
    Frame->B10  =   0x0B10;
    Frame->B11  =   0x0B11;
    Frame->B12  =   0x0B12;
    Frame->B13  =   0x0B13;
/*------------------------------------------------------------------------
   PASS THE CURRENT DP TO THE task
------------------------------------------------------------------------*/
    Frame->B14  =   ReturnCurrentDP();  /* by convention the data pointer is in B14. */
    Frame->B15  =   (unsigned int)StackBottom  ; /* C env Frame pointer */
    Frame->B16  =   0x0B16;
    Frame->B17  =   0x0B17;
    Frame->B18  =   0x0B18;
    Frame->B19  =   0x0B19;
    Frame->B20  =   0x0B20;
    Frame->B21  =   0x0B21;
    Frame->B22  =   0x0B22;
    Frame->B23  =   0x0B23;
    Frame->B24  =   0x0B24;
    Frame->B25  =   0x0B25;
    Frame->B26  =   0x0B26;
    Frame->B27  =   0x0B27;
    Frame->B28  =   0x0B28;
    Frame->B29  =   0x0B29;
    Frame->B30  =   0x0B30;
    Frame->B31  =   0x0B31;

    Frame->AMR_ =   0;

    /* little endian */
    /* Program Cache disabled ( 2 << 5 ) */
    /* Data Cache disabled    ( 2 << 2 ) */
    /* PGIE set and GIE disabled.  This will enable interrupts on ctx sw*/
    Frame->CSR_ =   (0<<8) + 2;

    Frame->IER_ =   0;  /* Once, the IER was set here.  This value is not being used. */
    Frame->IRP_ =   0xdeadbeef;

    Frame->B3   =   (unsigned int)task ;

	/*
	 * In this processor, pushing on the stack decrements the stack pointer.
	 * Within this function, "Frame" has been pointing to the first location
	 * of the stack frame.  In this processor, the correct value of the stack
	 * pointer is one word BEFORE the pushed frame data.  These lines place that
	 * address into "FirstFreeCellInStack".  Lint does not like the cast from the
	 * REGISTER_FRAME* to an int*.  Suppress the warning.
	 */

    FirstFreeCellInStack = (unsigned int *)Frame ;
    FirstFreeCellInStack--;

    return (FirstFreeCellInStack);
}

// ------------------------------------------------------------------------1
void timerInit(void)
{
   /*------------------------------------------------------------------------*/
   /* SETUP THE TIMER.                                                       */
   /*------------------------------------------------------------------------*/

   TIMER_1_BASE[ TIMER_CONTROL ] = 0;
   TIMER_1_BASE[ TIMER_PERIOD ] = ( ( CLOCK_PER_SEC / OS_TICKS_PER_SEC ) / 2 );            // set period register
   TIMER_1_BASE[ TIMER_COUNTER ] = 0x0;
   TIMER_1_BASE[ TIMER_CONTROL ] = ( 1 << 4 ) + ( 1 << 8 ) + ( 1 << 9 );    // C/P = clk mode, PWID=2 clk pulses, CLKSRC=CPU/8

   TIMER_1_BASE[ TIMER_CONTROL ] |= 1;    // turns on T1OUT

   TIMER_1_BASE[ TIMER_CONTROL ] |= ( 1 << 6 ) + ( 1 << 7 );    // start timer, GO=1, ~HLD=1

   /* Enable the timer interrupt and NMI.  Global, maskable interrupts remain off. */
   IER = 0x8002;
}

// ------------------------------------------------------------------------1
void  OSTCBInitHook (OS_TCB *ptcb)
{
    ptcb = ptcb;               /* Prevent Compiler warning. */
}

// ------------------------------------------------------------------------2
void  OSTaskCreateHook (OS_TCB *ptcb)
{
    ptcb = ptcb;               /* Prevent compiler warning    */
}

// ------------------------------------------------------------------------3
void  OSTaskDelHook (OS_TCB *ptcb)
{
    ptcb = ptcb;               /* Prevent compiler warning    */
}

// ------------------------------------------------------------------------4
void  OSTaskSwHook (void)
{
}

// ------------------------------------------------------------------------5
void  OSInitHookBegin (void)
{
}

// ------------------------------------------------------------------------6
void  OSInitHookEnd (void)
{
}

// ------------------------------------------------------------------------7
void  OSTaskIdleHook (void)
{
}

// ------------------------------------------------------------------------8
void  OSTaskStatHook (void)
{
}

// ------------------------------------------------------------------------9
void  OSTimeTickHook (void)
{
#if OS_TMR_EN > 0
    OSTmrTickCtr++;
    if (OSTmrTickCtr >= (OS_TICKS_PER_SEC / OS_TMR_CFG_TICKS_PER_SEC)) {
        OSTmrTickCtr = 0;
        OSTmrSignal();
    }
#endif
}

